/*
 *    Copyright (c) 2018-2025, nart All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: nart
 */
package com.nai365.nart.operation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nai365.nart.common.core.constant.SecurityConstants;
import com.nai365.nart.common.core.util.R;
import com.nai365.nart.common.security.util.SecurityUtils;
import com.nai365.nart.member.dto.SimpleMemberDto;
import com.nai365.nart.member.feign.RemoteMemberService;
import com.nai365.nart.operation.dto.PledgeParamDto;
import com.nai365.nart.operation.dto.PledgeRecordDto;
import com.nai365.nart.operation.dto.SpuDto;
import com.nai365.nart.operation.entity.PledgeDemand;
import com.nai365.nart.operation.entity.PledgeRecord;
import com.nai365.nart.operation.entity.PledgeRecordDetail;
import com.nai365.nart.operation.mapper.PledgeDemandMapper;
import com.nai365.nart.operation.mapper.PledgeRecordDetailMapper;
import com.nai365.nart.operation.mapper.PledgeRecordMapper;
import com.nai365.nart.operation.service.PledgeDemandService;
import com.nai365.nart.operation.service.PledgeRecordService;
import com.nai365.nart.operation.service.ProductService;
import com.nai365.nart.product.api.feign.RemoteSkuService;
import com.nai365.nart.product.entity.SkuInfo;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 质押记录
 *
 * @author baogs
 * @date 2022-07-01 11:13:17
 */
@Service
@AllArgsConstructor
public class PledgeRecordServiceImpl extends ServiceImpl<PledgeRecordMapper, PledgeRecord> implements PledgeRecordService {

	private final PledgeDemandMapper pledgeDemandMapper;
	private final PledgeRecordDetailMapper pledgeRecordDetailMapper;

	private final PledgeRecordMapper pledgeRecordMapper;

	private final RemoteSkuService remoteSkuService;

	private final RemoteMemberService remoteMemberService;

	private final ProductService productService;

	private final PledgeDemandService pledgeDemandService;

	@Override
	@Transactional
	@Klock(keys = {"#pledgeParam.pledgeDemandId"})
	public PledgeRecordDto pledge(PledgeParamDto pledgeParam) throws Exception {
		PledgeDemand pledgeDemand = pledgeDemandMapper.selectById(pledgeParam.getPledgeDemandId());
		if (pledgeDemand.getPlantAmount() - pledgeDemand.getActualAmount() < pledgeParam.getSkuList().size()) {
			throw new Exception("可质押数量不足，质押失败");
		}
		LocalDateTime now = LocalDateTime.now();
		if (now.isAfter(pledgeDemand.getEndTime())) {
			throw new Exception("质押活动已经结束！");
		}
		if (now.isBefore(pledgeDemand.getBeginTime())) {
			throw new Exception("质押活动尚未开始！");
		}
		List<SkuInfo> skuInfoList = getRemoteSkuList(pledgeParam.getSkuList());
		for (SkuInfo s : skuInfoList) {
			if (s.getPublishStatus() != 0) {
				throw new Exception("质押藏品中有不可用质押藏品，藏品编号为：" + s.getToken() + "#" + s.getSkuCode());
			}
		}
		PledgeRecord pledgeRecord = PledgeRecord.builder()
				.spuId(pledgeDemand.getSpuId())
				.pledgeDemandId(pledgeDemand.getId())
				.amount(pledgeParam.getSkuList().size())
				.status(1)
				.userId(SecurityUtils.getUser().getId())
				.beginTime(LocalDateTime.now())
				.planEndTime(LocalDateTime.now().plusDays(pledgeDemand.getTimeLimit()))
				.estimatedIncome(pledgeDemand.getIncome() * pledgeParam.getSkuList().size())
				.build();
		this.save(pledgeRecord);
		for (Long skuId : pledgeParam.getSkuList()) {
			PledgeRecordDetail pledgeRecordDetail = PledgeRecordDetail.builder()
					.pledgeRecordId(pledgeRecord.getId())
					.skuId(skuId)
					.spuId(pledgeDemand.getSpuId())
					.build();
			pledgeRecordDetailMapper.insert(pledgeRecordDetail);
		}
		pledgeDemand.setActualAmount(pledgeDemand.getActualAmount() + pledgeParam.getSkuList().size());
		pledgeDemandMapper.updateById(pledgeDemand);
		return pledgeRecord2dto(pledgeRecord, skuInfoList, pledgeDemand);
	}

	@Override
	public List<SkuInfo> findAblePledgeSku(Long pledgeDemandId) {
		PledgeDemand pledgeDemand = pledgeDemandMapper.selectById(pledgeDemandId);
		return remoteSkuService.findMySkuBySpuIdAndStatus(pledgeDemand.getSpuId(), 0).getData();
	}

	@Override
	public Page<PledgeRecordDto> page(Page<PledgeRecord> page, QueryWrapper<PledgeRecord> queryWrapper) {
		List<PledgeRecordDto> result = new ArrayList<>();
		//查询分页数据
		page = this.pledgeRecordMapper.selectPage(page, queryWrapper);
		Page<PledgeRecordDto> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
		//组装使用到的会员ID列表，SPU ID列表
		List<Long> spuIdList = new ArrayList<>();
		Set<Long> memberIdSet = new HashSet<>();
		Set<Long> pledgeDemandIdSet = new HashSet<>();
		for (PledgeRecord p : page.getRecords()) {
			if (p.getUserId() != null) {
				memberIdSet.add(p.getUserId());
			}
			if (p.getSpuId() != null) {
				spuIdList.add(p.getSpuId());
			}
			if (p.getPledgeDemandId() != null) {
				pledgeDemandIdSet.add(p.getPledgeDemandId());
			}
		}
		//查询质押需求数据
		Map<Long, PledgeDemand> pledgeDemandMap = new HashMap<>();
		if (!pledgeDemandIdSet.isEmpty()) {
			List<PledgeDemand> pledgeDemandList = pledgeDemandMapper.selectBatchIds(pledgeDemandIdSet);
			if (pledgeDemandList != null && !pledgeDemandList.isEmpty()) {
				for (PledgeDemand pd : pledgeDemandList) {
					pledgeDemandMap.put(pd.getId(), pd);
				}
			}
		}
		//远程查询SPU，会员数据
		Map<Long, SpuDto> spuDtoMap = this.productService.getSpuInfoMapByIds(spuIdList);
		Map<Long, SimpleMemberDto> memberMap = this.getMemberMapByIds(memberIdSet);
		//组装结果数据
		for (PledgeRecord p : page.getRecords()) {
			PledgeRecordDto vo = new PledgeRecordDto();
			BeanUtils.copyProperties(p, vo);
			LambdaQueryWrapper<PledgeRecordDetail> lqw = Wrappers.lambdaQuery();
			lqw.eq(PledgeRecordDetail::getPledgeRecordId, p.getId());
			List<Long> temp = new ArrayList<>();
			for (PledgeRecordDetail prd : pledgeRecordDetailMapper.selectList(lqw)) {
				temp.add(prd.getSkuId());
			}
			vo.setSkuList(getRemoteSkuList(temp));
			if (pledgeDemandMap.get(p.getPledgeDemandId()) != null) {
				vo.setPledgeDemand(pledgeDemandService.pledgeDemand2PledgeDemandDto(
						pledgeDemandMap.get(p.getPledgeDemandId()), spuDtoMap
				));
			}
			vo.setMember(memberMap.get(p.getUserId()));
			result.add(vo);
		}
		resultPage.setRecords(result);
		return resultPage;
	}


	private List<SkuInfo> getRemoteSkuList(List<Long> spuIdList) {
		List<SkuInfo> result = new ArrayList<>();
		if (spuIdList != null && spuIdList.size() > 0) {
			R<List<SkuInfo>> remoteResult = remoteSkuService.infos(spuIdList, SecurityConstants.FROM_IN);
			if (remoteResult.getCode() == 0 && remoteResult.getData() != null && !remoteResult.getData().isEmpty()) {
				List<SkuInfo> skuList = remoteResult.getData();
				if (skuList != null) {
					result = skuList;
				}
			}
		}
		return result;
	}

	private Map<Long, SimpleMemberDto> getMemberMapByIds(Collection<Long> ids) {
		Map<Long, SimpleMemberDto> result = new HashMap<>();
		R<List<SimpleMemberDto>> remoteResult = this.remoteMemberService.listByIds(ids);
		if (remoteResult.getCode() == 0 && remoteResult.getData() != null && !remoteResult.getData().isEmpty()) {
			for (SimpleMemberDto member : remoteResult.getData()) {
				result.put(member.getId(), member);
			}
		}
		return result;
	}

	@Override
	@Transactional
	public PledgeRecordDto cancel(Long pledgeRecordId) {
		//设置质押记录为已取消
		PledgeRecord pledgeRecord = this.getById(pledgeRecordId);
		pledgeRecord.setStatus(3);
		this.updateById(pledgeRecord);
		//取消sku质押状态
		List<SkuInfo> skuInfoList = getSkuListByRecordId(pledgeRecordId);
		for (SkuInfo sku : skuInfoList) {
			sku.setPublishStatus(0);
			remoteSkuService.updateById(sku);
		}
		//返回质押记录dto
		PledgeDemand pledgeDemand = pledgeDemandMapper.selectById(pledgeRecord.getPledgeDemandId());
		return pledgeRecord2dto(pledgeRecord, skuInfoList, pledgeDemand);
	}

	private PledgeRecordDto pledgeRecord2dto(PledgeRecord pledgeRecord, List<SkuInfo> skuInfoList, PledgeDemand pledgeDemand) {
		PledgeRecordDto vo = new PledgeRecordDto();
		BeanUtils.copyProperties(pledgeRecord, vo);
		vo.setSkuList(skuInfoList);
		List<Long> spuIdList = new ArrayList<>();
		spuIdList.add(pledgeRecord.getSpuId());
		Map<Long, SpuDto> spuDtoMap = this.productService.getSpuInfoMapByIds(spuIdList);
		vo.setPledgeDemand(pledgeDemandService.pledgeDemand2PledgeDemandDto(pledgeDemand, spuDtoMap));
		Set<Long> memberIdSet = new HashSet<>();
		memberIdSet.add(SecurityUtils.getUser().getId());
		Map<Long, SimpleMemberDto> memberMap = this.getMemberMapByIds(memberIdSet);
		vo.setMember(memberMap.get(pledgeRecord.getUserId()));
		return vo;
	}

	private List<SkuInfo> getSkuListByRecordId(Long recordId) {
		LambdaQueryWrapper<PledgeRecordDetail> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(PledgeRecordDetail::getPledgeRecordId, recordId);
		List<PledgeRecordDetail> pledgeRecordDetailList = pledgeRecordDetailMapper.selectList(queryWrapper);
		Set<Long> skuIdList = new HashSet<>();
		if (pledgeRecordDetailList != null && !pledgeRecordDetailList.isEmpty()) {
			for (PledgeRecordDetail pledgeRecordDetail : pledgeRecordDetailList) {
				skuIdList.add(pledgeRecordDetail.getSkuId());
			}
		}
		List<SkuInfo> skuInfoList = new ArrayList<>();
		if (!skuIdList.isEmpty()) {
			R<List<SkuInfo>> remote = remoteSkuService.infos(skuIdList, SecurityConstants.FROM_IN);
			if (remote.getCode() == 0 && remote.getData() != null && !remote.getData().isEmpty()) {
				skuInfoList = remote.getData();
			}
		}
		return skuInfoList;
	}

	@Override
	public PledgeRecordDto getPledgeRecordDtoById(Long id) {
		PledgeRecord pledgeRecord = this.getById(id);
		PledgeDemand pledgeDemand = pledgeDemandMapper.selectById(pledgeRecord.getPledgeDemandId());
		return pledgeRecord2dto(pledgeRecord, getSkuListByRecordId(id), pledgeDemand);
	}
}
